#pragma once

#include <iostream>
#include <pthread.h>
#include <queue>
#include "task.hpp"

template<typename T>
class BlockQueue
{
public:

    BlockQueue()
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_c_cond, nullptr);
        pthread_cond_init(&_p_cond, nullptr);
    }

    T pop()
    {
        //  取数据
        pthread_mutex_lock(&_mutex);
        while(_bq.size() == 0)  // 没有数据了 就要等其他线程写数据
        {
            pthread_cond_wait(&_c_cond, &_mutex);  // 放入 消费者队列里面等待
        }

        T t = _bq.front();
        _bq.pop();

        pthread_cond_signal(&_p_cond); // 告诉生产 有空间了
        pthread_mutex_unlock(&_mutex);
        return t;
    }

    void push(const T& t)
    {
        pthread_mutex_lock(&_mutex);
        while(_bq.size() == _maxcap)  // 条件空间不足，就不能继续写
        {
            pthread_cond_wait(&_p_cond, &_mutex);   // 放入 生产者 队列里等待
        }

        _bq.push(t);
        pthread_cond_signal(&_c_cond);   // 写入了数据 告诉 消费者消费
        pthread_mutex_unlock(&_mutex);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_c_cond);
        pthread_cond_destroy(&_p_cond);
    }

private:
    std::queue<T> _bq;
    pthread_mutex_t _mutex;
    pthread_cond_t _c_cond;
    pthread_cond_t _p_cond;
    int _maxcap = 10;
};